#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>
#include<mpi.h>

# define qtdePalavras 65200
# define MAXPALAVRA 6
# define ALFABETO 26
# define MAXLOOP 1000

typedef struct {
    char pal[30];
}palav;

// variaveis globais

palav *dicionario2;
palav *dicionario3;
palav *dicionario4;
palav *dicionario5;
int ind_max = 0, ind_max2 = 0, ind_max3 = 0, ind_max4 = 0, ind_max5 = 0;

int busca_palavra(char *palavra,palav *dicionario, int ind_max){
	int i;
	for(i=0;i<ind_max; i++){
		if(strcmp(dicionario[i].pal, palavra) == 0)
			return i;
	}
	return -1;
}

int gera_aleatorio(char *word, int rank, int *vet_encontradas){
	int i = 0, indice= -1, tamword = 0;

	for(i=0;i<MAXPALAVRA; i++){
		word[i] = (rand()%ALFABETO) + 97;
		word[i+1] = '\0';
		tamword = strlen(word);

		switch(tamword){
            case 2:
                indice = busca_palavra(word,dicionario2,ind_max2);
                if(indice >= 0){
                    if(vet_encontradas[indice] == 0){
                        return indice;
                    }
                    break;//precisa?
                }
                break;//precisa?
            case 3:
                indice = busca_palavra(word,dicionario3,ind_max3);
                if(indice >= 0){
                    indice = indice + ind_max2;
                    if(vet_encontradas[indice] == 0){
                        return indice;
                    }
                    break;//precisa?
                }
                break;//precisa?
            case 4:
                indice = busca_palavra(word,dicionario4,ind_max4);
                if(indice >= 0){
                    indice = indice + ind_max2 + ind_max3;
                    if(vet_encontradas[indice] == 0){
                        return indice;
                    }
                    break;//precisa?
                }
                break;//precisa?
            case 5:
                indice = busca_palavra(word,dicionario5,ind_max5);
                if(indice >= 0){
                    indice = indice + ind_max2 + ind_max3 + ind_max4;
                    if(vet_encontradas[indice] == 0){
                        return indice;
                    }
                    break;//precisa?
                }
                break;//precisa?
		}//switch
	}//for

	return -1; //nao achou

}

float calcula_porcentagem(int *vetor_encontrada){
	int i=0, soma=0;
	for(i=0;i<ind_max;i++){
		soma=soma+vetor_encontrada[i];
	}

	return (float)soma/(float)(ind_max);
}
// funcao principal
int main (int argc, char *argv[]) {

	FILE * arqIn;

	char word[20];
	unsigned i=0, j=0, k=0;

    clock_t inicio, fim;
    double tempo;

	unsigned tam_pal;

	// variaveis usadas para MPI
    int numprocs, rank, namelen, rc;
    char processor_name[MPI_MAX_PROCESSOR_NAME];

	if(!(arqIn = fopen("Max5_form.txt", "r"))){
		printf("Erro ao abrir o arquivo!\n\n");
		return -1;
	}
	//printf("Abriu o arquivo\n");

        //tam 2
		fscanf(arqIn, "%d\n", &ind_max2);
		fscanf(arqIn, "%d\n", &tam_pal);
		//printf("%d palavras de tamanho %d\n", ind_max2, tam_pal);
		dicionario2 = malloc((ind_max2)*sizeof(palav));
		//printf("Alocou o primeiro vetor, com tamanho ind_max\n");

		//printf("Tentativa de carregar as palavras de tamanho %d\n", tam_pal);
		for(i=0; i < ind_max2 ;i++){ //carregando o dicionario para a memoria
			/*for(k=0;k < tam_pal; k++){

				printf("i = %d, k= %d\n", i, k);
				dicionario2[i][k] = (char)fgetc(arqIn);
			}
			dicionario2[i][k] = '\0';*/

			fscanf(arqIn, "%s\n", dicionario2[i].pal);
			//dicionario2[i+1] = '\0';
			//printf("Carregou palavra = %s\n", dicionario2[i].pal);
		}

		//tam 3
		fscanf(arqIn, "%d\n", &ind_max3);
		fscanf(arqIn, "%d\n", &tam_pal);
		//printf("%d palavras de tamanho %d\n", ind_max3, tam_pal);
		dicionario3 = malloc((ind_max3)*sizeof(palav));
		//printf("Alocou o primeiro vetor, com tamanho ind_max\n");

		//printf("Tentativa de carregar as palavras de tamanho %d\n", tam_pal);
		for(i=0; i < ind_max3 ;i++){ //carregando o dicionario para a memoria

			fscanf(arqIn, "%s\n", dicionario3[i].pal);
			//printf("Carregou palavra = %s\n", dicionario3[i].pal);
		}

		//tam 4
		fscanf(arqIn, "%d\n", &ind_max4);
		fscanf(arqIn, "%d\n", &tam_pal);
		//printf("%d palavras de tamanho %d\n", ind_max4, tam_pal);
		dicionario4 = malloc((ind_max4)*sizeof(palav));
		//printf("Alocou o primeiro vetor, com tamanho ind_max\n");

		//printf("Tentativa de carregar as palavras de tamanho %d\n", tam_pal);
		for(i=0; i < ind_max4 ;i++){ //carregando o dicionario para a memoria

			fscanf(arqIn, "%s\n", dicionario4[i].pal);
			//printf("Carregou palavra = %s\n", dicionario4[i].pal);
		}

		//tam 5
		fscanf(arqIn, "%d\n", &ind_max5);
		fscanf(arqIn, "%d\n", &tam_pal);
		//printf("%d palavras de tamanho %d\n", ind_max5, tam_pal);
		dicionario5 = malloc((ind_max5)*sizeof(palav));
		//printf("Alocou o primeiro vetor, com tamanho ind_max\n");

		//printf("Tentativa de carregar as palavras de tamanho %d\n", tam_pal);
		for(i=0; i < ind_max5 ;i++){ //carregando o dicionario para a memoria

			fscanf(arqIn, "%s\n", dicionario5[i].pal);
			//printf("Carregou palavra = %s\n", dicionario5[i].pal);
		}

	fclose(arqIn);
	MPI_Status Stat;
    rc = MPI_Init(&argc, &argv);

    if(rc != MPI_SUCCESS){
            printf("Falha ao iniciar MPI\n\n");
            exit(-1);
    }
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Get_processor_name(processor_name, &namelen);

    int encontrada[numprocs][qtdePalavras];
    srand(time(NULL) + rank);

    ind_max = ind_max2 + ind_max3 + ind_max4 + ind_max5;
	for(j=0;j<numprocs;j++){
		for(i=0;i<ind_max;i++){
			encontrada[j][i] = 0;
		}
		for(i=ind_max;i<qtdePalavras;i++){
			encontrada[j][i] = -1;
		}
	}

    if(rank == 0){ // mestre
		int nao_terminou=1;
		float porcentagem_encontrada = 0.0, porcentagem_anterior = 0.0, diferenca = 0.0;
		inicio = clock(); //loop de calculo
				printf("-------------------------------------------------------------\n");
				printf("Starting clock at time = 0.00\n");
		while(nao_terminou){


			for(k=1;k<numprocs;k++){
				MPI_Recv(encontrada[k], ind_max, MPI_INT, k, 1, MPI_COMM_WORLD, &Stat);
			}
			/*
			* Calcula % de palavras encontradas
			* printa a cada 10%
			* termina se encontrou 100% :)
			*/

			for(k=1;k<numprocs;k++){ // indice dos filhos
				for(j=0;j<ind_max;j++){ //percorre o vetor de palavras encontradas de cada filho
					if(encontrada[k][j] == 1){
						encontrada[0][j] = 1;
					}
				}
			}

			porcentagem_anterior = porcentagem_encontrada;
			porcentagem_encontrada = calcula_porcentagem(encontrada[0]);
			diferenca = diferenca + (porcentagem_encontrada - porcentagem_anterior);
			if((porcentagem_encontrada == 1.00) || (porcentagem_encontrada >= 0.9999)){
				printf("-------------------------------------------------------------\n");
				printf("Finished %.2f percent in", porcentagem_encontrada*100);
				nao_terminou = 0;
			}
			else if (diferenca >= 0.10){
				fim = clock();
				tempo = ((fim-inicio)/(CLOCKS_PER_SEC/1000));
				printf("Found just  %.2f percent in clock time = %.2f\n", porcentagem_encontrada*100, tempo);
				diferenca = 0.0;
			}

			for(k=1;k<numprocs;k++)
				MPI_Send(&porcentagem_encontrada, 1, MPI_FLOAT, k, 1, MPI_COMM_WORLD);

		}
		fim = clock();
		tempo = ((fim-inicio)/(CLOCKS_PER_SEC/1000));
		printf(" %.2f miliseconds\n", tempo);
		printf("-------------------------------------------------------------\n");
    }
	else{ // escravos
		int continua = 1, multifactor = 1;
		float porcentagem_encontrada = 0.0, porcentagem_anterior = 0.0, diferenca = 0.0;

		while(1){
			while(continua < (MAXLOOP * multifactor)){
				int indice = gera_aleatorio(word, rank, encontrada[rank]);
				/*
				Se encontrou palavra, marca no vetor encontrada
				*/
				//int indice = busca_palavra("aback");

				if(indice >= 0){
					encontrada[rank][indice] = 1;
					//printf("Rank: %d encontrou: %s, indice: %d\n", rank, word, indice);
				}

				continua++;
			}
			MPI_Send(encontrada[rank], ind_max, MPI_INT, 0, 1, MPI_COMM_WORLD);
			porcentagem_anterior = porcentagem_encontrada;
			diferenca = diferenca + (porcentagem_encontrada - porcentagem_anterior);
			MPI_Recv(&porcentagem_encontrada, 1, MPI_FLOAT, 0, 1, MPI_COMM_WORLD, &Stat);
			if((porcentagem_encontrada >= 0.9999) || (porcentagem_encontrada == 1.000))
				break;
			else if(diferenca >= 0.10){
				multifactor *= 10;
				diferenca = 0.0;
			}
			continua = 1;
		}
	}

	MPI_Barrier(MPI_COMM_WORLD);
	MPI_Finalize();

	return 0;
}
